#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
#include <unordered_map>
#include "../comm/expand_file_exist.hpp"
#include "../comm/log.hpp"
using namespace Log;
using namespace expand;
// model模块提供对数据的处理

struct Question
{
    // list文件中的内容
    int number;        // 题目编号
    std::string name;  // 题目名
    std::string level; // 难度
    int cpu_limit;     // 时间限制
    int mem_limit;     // 空间限制

    // description文件中的内容
    std::string description; // 题目的详细描述
    std::string head;        // 预定义的头文件
    std::string tail;        // 测试代码
    std::string body;        // 给用户的代码
};

// 题解信息
struct Solve
{
    int number; // 题目编号
    std::string title; // 题解名
    std::string solve; // 题解正文
    std::string solve_code; // 题解代码
    std::string author; // 题解作者
};

class Model
{
private:
    std::unordered_map<int, Question> questions;                         // kv保存每一道题目的信息
    const std::string question_list_path = "./questions/questions.list"; // list文件的路径
    const std::string question_description_path = "./questions/";        // 题目详细描述文件的路径，后面部分待填
public:
    Model()
    {
        loadQuestions();
    }

    bool loadQuestions()
    {
        // 将每一道题目的信息全部加载到 questions 中
        std::ifstream in(question_list_path);
        if (!in.is_open())
        {
            logMessage(FATAL, "%s", "题目列表文件打开失败");
            return false;
        }
        std::string line;
        while (std::getline(in, line))
        {
            // 逐行读取list文件

            std::vector<std::string> tokens;
            StringUtil::split(line, &tokens, ":");
            if (tokens.size() != 5)
            {
                logMessage(WARNING, "%s", "题目列表中存在格式错误");
                return false;
            }

            //  填充字段
            //  1:hello world:简单:1:10000
            Question q;
            q.number = atoi(tokens[0].c_str());
            q.name = tokens[1];
            q.level = tokens[2];
            q.cpu_limit = atoi(tokens[3].c_str());
            q.mem_limit = atoi(tokens[4].c_str());

            // 加载description文件
            std::string desc_path = question_description_path;
            desc_path += std::to_string(q.number);
            desc_path += "/";

            // 填充题目的代码部分
            if (!Expand::readFromFile(desc_path + "description.txt", &(q.description), true))
            {
                logMessage(WARNING, "加载题目描述出错 [%s: %d]", __FILE__, __LINE__);
                return false;
            }
            if (!Expand::readFromFile(desc_path + "head.hpp", &(q.head), true))
            {
                logMessage(WARNING, "加载题目头文件出错 [%s: %d]", __FILE__, __LINE__);
                return false;
            }
            if (!Expand::readFromFile(desc_path + "tail.cpp", &(q.tail), true))
            {
                logMessage(WARNING, "加载题目测试代码出错 [%s: %d]", __FILE__, __LINE__);
                return false;
            }
            if (!Expand::readFromFile(desc_path + "body.cpp", &(q.body), true))
            {
                logMessage(WARNING, "加载题目用户预置代码出错 [%s: %d]", __FILE__, __LINE__);
                return false;
            }

            // 插入哈希表中
            questions.insert({q.number, q});
        }

        logMessage(DEBUG, "添加所有题目完毕!! [%s: %d]", __FILE__, __LINE__);
        return true;
    }

    bool getAllQuestions(std::vector<Question> *out)
    {
        // 得到所有题目
        if (questions.empty())
        {
            logMessage(WARNING, "%s", "题单为空...");
            return false;
        }
        for (auto &it : questions)
        {
            out->push_back(it.second);
        }
        return true;
    }

    bool getOneQuestion(int number, Question *out)
    {
        // 得到指定的一道题目
        // 判断number是否合法
        auto it = questions.find(number);
        if (it == questions.end())
        {
            logMessage(ERROR, "%s", "要查询的题目不存在");
            return false;
        }
        *(out) = it->second;
        return true;
    }
    ~Model() {}
};